/***************************************************************************
 *   Copyright (C) 2006 by Harish Kukreja                                  *
 *   harish.kukreja@gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//
// C++ Implementation: objects
//
// Description: Definitions of various physical Objects that are found in the Physiks interactions
//              environment.
//
// Author: Harish Kukreja <harish.kukreja@gmail.com>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//


#include <physiksbase/objects.h>
#include <GL/glut.h>
#include <GL/gl.h>

using PhysiksBase::Vector;

// Definitions for PhysiksBase::PhysicalObject ////////////////////////////////

PhysiksBase::PhysicalObject::PhysicalObject() : position(3, 0.0), velocity(3, 0.0), net_force(3, 0.0), gravitational_field(*this), coulomb_acceleration_field(*this) {
    mass = charge = 0.0;
/*    position = new Vector(3, 0.0);
    velocity = new Vector(3, 0.0);
    net_force = new Vector(3, 0.0);
    
    gravitational_field = new NewtonianGravitationalField(*this);
    coulomb_force_field = new CoulombForceField(*this);*/
}

PhysiksBase::PhysicalObject::PhysicalObject(double m, double c, const Vector &pos, 
                                            const Vector &vel) : position(pos), velocity(vel), net_force(3, 0.0), gravitational_field(*this), coulomb_acceleration_field(*this) {
    mass = m;
    charge = c;
/*    position = new Vector(pos);
    velocity = new Vector(vel);
    net_force = new Vector(3, 0.0);
    gravitational_field = new NewtonianGravitationalField(*this);
    coulomb_force_field = new CoulombForceField(*this);*/
}

PhysiksBase::PhysicalObject::~PhysicalObject() {}

void PhysiksBase::PhysicalObject::draw() const {
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(position[0], position[1], position[2]);
    glutSolidSphere(1.0, 180, 180);
    glPopMatrix();
}


// Definitions for PhysiksBase::ExtendedObject ////////////////////////////////

PhysiksBase::ExtendedObject::ExtendedObject() : PhysicalObject(), angular_velocity(3, 0.0) {
}

PhysiksBase::ExtendedObject::ExtendedObject(double mass, double charge, const Vector &position, const Vector &velocity) : PhysicalObject(mass, charge, position, velocity), angular_velocity(3, 0.0) {
}

PhysiksBase::ExtendedObject::~ExtendedObject() {}


// Definitions for PhysiksBase::Sphere ////////////////////////////////////////

PhysiksBase::Sphere::Sphere() : ExtendedObject() {
    radius = 1.0;
}

PhysiksBase::Sphere::Sphere(double mass, double charge, const Vector &position,
                            const Vector &velocity, double radius) : ExtendedObject(0.0, 0.0, position, velocity) {
    this->radius = radius;
}

PhysiksBase::Sphere::~Sphere() {}

void PhysiksBase::Sphere::draw() const {
    glTranslatef(position[0], position[1], position[2]);
    glutSolidSphere(radius, 180, 180);
}

double PhysiksBase::Sphere::get_elasticity() const {
    return elasticity;
}

void PhysiksBase::Sphere::set_elasticity(double val) {
    elasticity = val;
}

double PhysiksBase::Sphere::get_radius() const {
    return radius;
}

void PhysiksBase::Sphere::set_radius(double radius) {
    this->radius = radius;
}



// Definitions for PhysiksBase::Plane /////////////////////////////////////////

PhysiksBase::Plane::Plane(const Vector &normal, const Vector &origin) : ExtendedObject() {
    normal_vec = new Vector(normal.normalize());
    position.set(origin);
    unbounded = true;
}

PhysiksBase::Plane::Plane(const Vector &vec1, const Vector &vec2, const Vector &origin) : ExtendedObject() {
    basis_vec1 = new Vector(vec1);
    basis_vec2 = new Vector(vec2);
    normal_vec = new Vector(vec1.cross(vec2).normalize());
    position.set(origin);
    unbounded = false;
}

PhysiksBase::Plane::~Plane() {
    delete basis_vec1, basis_vec2, normal_vec;
}

void PhysiksBase::Plane::draw() const {
}

void PhysiksBase::Plane::bounded(bool flag) {
    unbounded = !flag;
}

bool PhysiksBase::Plane::bounded() const {
    return !unbounded;
}

bool PhysiksBase::Plane::contains(const Vector &vec) const {
// One would check for a solution to the system a*v_1 + b*v_2 = vec. What is the most efficient
// way to do so?
    return false;
}

Vector PhysiksBase::Plane::normal() const {
    return Vector(*normal_vec);
}

void PhysiksBase::Plane::set_normal(const Vector &norm) {
    normal_vec->set(norm.normalize());
}
